package org.eoti.game.roshambo;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * The MIT License
 * <p/>
 * Copyright (c) 2009 Malachi de AElfweald (malachid@gmail.com)
 * <p/>
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * <p/>
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 * <p/>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
public class Roshambo<WEAPON extends Weapon<WEAPON>, PLAYERID, PLAYER extends Player<PLAYERID, WEAPON>, RULES extends RuleMonger<WEAPON,PLAYERID,PLAYER>>
{
	private CopyOnWriteArrayList<PLAYER> players;
	private RULES ruleMonger;
	private int round = 1;
	private ConcurrentHashMap<PLAYERID, Stats> stats;

	public Roshambo(RULES ruleMonger)
	{
		this.ruleMonger = ruleMonger;
		this.players = new CopyOnWriteArrayList<PLAYER>();
		stats = new ConcurrentHashMap<PLAYERID, Stats>();
	}

	public void addPlayer(PLAYER player)
	{
		players.add( player );
		stats.put( player.getId(), new Stats() );
	}

	public List<Judgement<WEAPON,PLAYERID,PLAYER>> playRound()
	{
		ArrayList<Judgement<WEAPON,PLAYERID,PLAYER>> toRet = new ArrayList<Judgement<WEAPON,PLAYERID,PLAYER>>();
		for(PLAYER player : players)
			player.log(player.takeTurn());
		
		Judgement<WEAPON,PLAYERID,PLAYER> judgement = null;
//		System.out.format("\nRound: %d\n", round++);
		for(int i=0; i<players.size(); i++)
		{
			PLAYER player1 = players.get(i);
			for(int j=i+1; j<players.size(); j++)
			{
				PLAYER player2 = players.get(j);
				if(player1 == player2) continue;
				judgement = ruleMonger.judge( new Challenge<WEAPON,PLAYERID,PLAYER>(player1, player2) );
				toRet.add(judgement);
//				System.out.format("%s\n", judgement);
				switch(judgement.getWinner())
				{
					case Player1:
						stats.get( player1.getId() ).wins++;
						stats.get( player2.getId() ).losses++;
						break;
					case Player2:
						stats.get( player1.getId() ).losses++;
						stats.get( player2.getId() ).wins++;
						break;
					default:
						stats.get( player1.getId() ).ties++;
						stats.get( player2.getId() ).ties++;
						break;
				}
			}
		}
		return toRet;
	}

	public void report()
	{
		report(System.out);
	}
	public void report(PrintStream out)
	{
		out.format("\n\nREPORT:\n");
		for(PLAYER player : players)
		{
			Stats stat = stats.get(player.getId());
			out.format("%15s:\t%2d wins\t%2d losses\t%2d ties\n", player.getId(), stat.wins, stat.losses, stat.ties);
		}
	}

	class Stats
	{
		private int wins, losses, ties;
		public Stats(){}
	}
}
